package com.base.lock;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import com.base.lock.annotation.Lock;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 分布式锁Key生成器
 *
 * @author carl
 */
public class DefaultLockKeyBuilder implements LockKeyBuilder {


    private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

    private static final ExpressionParser PARSER = new SpelExpressionParser();

    @Override
    public String buildKey(MethodInvocation invocation, Lock lock) {
        StringBuilder sb = new StringBuilder();
        Method method = invocation.getMethod();
        if(ArrayUtil.isEmpty(lock.prefix())){
            sb.append(":").append(method.getDeclaringClass().getName()).append(".").append(method.getName()).append("#");
        }else {
            sb.append(StringUtils.collectionToDelimitedString(CollUtil.newArrayList(lock.prefix()), lock.delimiter(), "", lock.delimiter()));
        }
        if (lock.keys().length > 1 || !"".equals(lock.keys()[0])) {
            sb.append(getSpelDefinitionKey(lock.keys(), method, invocation.getArguments(),lock.delimiter()));
        }
        return sb.toString();
    }

    protected String getSpelDefinitionKey(String[] definitionKeys, Method method, Object[] parameterValues,String delimiter) {
        EvaluationContext context = new MethodBasedEvaluationContext(null, method, parameterValues, NAME_DISCOVERER);
        List<String> definitionKeyList = new ArrayList<>(definitionKeys.length);
        for (String definitionKey : definitionKeys) {
            if (definitionKey != null && !definitionKey.isEmpty()) {
                String key = PARSER.parseExpression(definitionKey).getValue(context).toString();
                definitionKeyList.add(key);
            }
        }
        return StringUtils.collectionToDelimitedString(definitionKeyList, delimiter, "", "");
    }


}
